#include <simulatorV1/parser/parser.h>
#include <simulatorV1/lexer/id.h>
#include <simulatorV1/lexer/num.h>
#include <simulatorV1/log/report.h>

Parser::Parser() {
    m_lexer = std::make_unique<Lexer>();
};

void Parser::move() {
    m_look = m_lexer->tokenize();
}

bool Parser::match(Tag need) {
    if (m_look->getTag() == need) {
        move();
        return true;
    } else {
        return false;
    }
}

void Parser::analysis(std::string command) {
    m_lexer->loadBuffer(command);
    move();
    m_programNode = parseProgram();
}

std::shared_ptr<ProgramNode> Parser::parseProgram() {
    if (m_look->getTag() == Tag::END) {
        return nullptr;
    } else {
        std::shared_ptr<ProgramNode> programNode = std::make_shared<ProgramNode>();
        programNode->m_functions = parseFunctions();
        return programNode;
    }
}

std::vector<std::shared_ptr<FunctionNode>> Parser::parseFunctions() {
    if (m_look->getTag() == Tag::ID) {
        std::vector<std::shared_ptr<FunctionNode>> functionNodes;
        functionNodes.emplace_back(parseFunction());
        if (m_look->getTag() == Tag::ID) {
            auto functions = parseFunctions();
            for (auto &function: functions) {
                functionNodes.emplace_back(function);
            }
            return functionNodes;
        } else if (m_look->getTag() == Tag::END) {
            return functionNodes;
        } else {
            fatalMacro("函数格式不正确");
        }

    } else {
        // $
        return {};
    }
}

std::shared_ptr<FunctionNode> Parser::parseFunction() {
    std::shared_ptr<FunctionNode> functionNode = std::make_shared<FunctionNode>();
    functionNode->m_funcName = parseFuncName();
    if (m_look->getTag() == Tag::SEMICOLON || m_look->getTag() == Tag::LPAREN) {
        functionNode->m_parameters = parseFuncTail();
    } else {
        fatalMacro("函数参数格式不正确");
    }
    return functionNode;
}

std::string Parser::parseFuncName() {
    auto id = std::dynamic_pointer_cast<Id>(m_look);
    if (id == nullptr) {
        fatalMacro("parser function name error");
    }
    std::string funcName;
    funcName = id->getName();
    move();
    return funcName;
}

std::vector<std::shared_ptr<AstNode>> Parser::parseFuncTail() {
    if (match(Tag::SEMICOLON)) {
        return {};
    } else {
        std::vector<std::shared_ptr<AstNode>> params;
        // eat(
        if (!match(Tag::LPAREN)) {
            fatalMacro("Function does not have a left parenthesis");
        }
        if (m_look->getTag() == Tag::NUM || isMatchReg()) {
            params = parsePara();
        } else {
            fatalMacro("函数参数格式不正确");
        }
        // eat )
        if (!match(Tag::RPAREN)) {
            fatalMacro("Function does not have a right parenthesis");
        }
        if (!match(Tag::SEMICOLON)) {
            fatalMacro("Function does not have a semicolon");
        }
        return params;
    }
}

std::vector<std::shared_ptr<AstNode>> Parser::parsePara() {
    if (m_look->getTag() == Tag::RPAREN) {
        return {};
    } else {
        std::vector<std::shared_ptr<AstNode>> params;
        params.emplace_back(parseParaData());
        if (m_look->getTag() == Tag::COMMA || m_look->getTag() == Tag::RPAREN) {
            auto anotherParams = parseParaList();
            for (auto &param: anotherParams) {
                params.push_back(param);
            }
        } else {
            fatalMacro("函数参数格式不正确");
        }
        return params;
    }
}

std::vector<std::shared_ptr<AstNode>> Parser::parseParaList() {
    if (match(Tag::COMMA)) {
        std::vector<std::shared_ptr<AstNode>> params;
        params.emplace_back(parseParaData());
        if (m_look->getTag() == Tag::COMMA || m_look->getTag() == Tag::RPAREN) {
            auto otherParams = parseParaList();
            for (auto &param: otherParams) {
                params.emplace_back(param);
            }
        } else {
            fatalMacro("函数参数格式不正确");
        }
        return std::move(params);
    } else {
        return {};
    }
}

std::shared_ptr<AstNode> Parser::parseParaData() {
    if (m_look->getTag() == Tag::NUM) {
        std::shared_ptr<ConstantNode> constantNode = std::make_shared<ConstantNode>();
        auto num = std::dynamic_pointer_cast<Num>(m_look);
        if (num == nullptr) {
            fatalMacro("该单词不为一个常数");
        }
        constantNode->m_value = num->m_val;
        move(); // eat number
        return constantNode;
    } else {
        return parseReg();
    }
}

std::shared_ptr<AstNode> Parser::parseReg() {
    std::shared_ptr<RegNode> regNode = std::make_shared<RegNode>();
    regNode->m_regKind = m_look->getTag();
    move(); // eat reg
    return regNode;
}

bool Parser::isMatchReg() {
    auto tag = m_look->getTag();
    if (tag >= Tag::A0 && tag <= Tag::B31) {
        return true;
    }
    return false;
}


std::shared_ptr<ProgramNode> Parser::getProgramNode() {
    return m_programNode;
}